

/**
 * @typedef MenuClickCallBack
 * @description chart range selector menu click call back
 * @type {function}
 * @param {string} type - type
 * @param {string} count - count
 * @param {string} el - menu element
 */



/**
 * @class
 * @param {*} options 
 */
function PilotChart(options) {
    this.dataProvider = null;
    this.loading = false;
    this.chartConfig = null;
    this.highChart = null;
    this.title = null;
    this.processConfigOn = false;
    this.graphInfo = {};
    this.chartType = "line";
    this.sampleInterval = 60 * 1000;
    this.maxDataPoint = 55;
    this.logger = console;
    this.chartTypeSelector = null;
    this.cachedSampleData = null;
    this.axisType = null;
    this.intelligentAxis = null;
    this.percentile = null;
    this._init();
}


PilotChart.prototype._init = function () {
    this.chartTypeSelector = document.getElementById("select_chartType");
    this.setClickRangeSelectorCallback();
    this.setChartTypeSelectCallback();
}

PilotChart.prototype.isDataSampled = function(){
    return this.sampleInterval > 0;
}

PilotChart.prototype.initChartWithConfig = function (chartConfig) {
    var self = this;
    if(isValued(chartConfig.dataOptions) && isValued(chartConfig.dataOptions.sampleInterval)){
        var sampleInterval = chartConfig.dataOptions.sampleInterval;
        if(sampleInterval<=0){
            self.maxDataPoint = chartConfig.dataOptions.maxDataPoint;
            self.sampleInterval = sampleInterval;
        }else{
            self.sampleInterval = sampleInterval;
        }

    }else{
        console.error("chartConfig should have sampleInterval field")
    }
    var title = chartConfig.chartName || chartConfig.title;
    self.setTitle(title)
    if (self.processConfigOn) {
        self.logger.info("Config command active.  Ignore..");
        return;
    }
    self.logger.log("Processing Config: ", title, chartConfig);
    self.processConfigOn = true;
    self.chartType = chartConfig.chartType.toLowerCase();
    self.chartTypeSelector.value = self.chartType;
    if (self.graphInfo.graphConfig) {
        chartConfig = mergeRecursive(self.graphInfo.graphConfig, chartConfig);
    } else {
        self.graphInfo.graphConfig = chartConfig;
    }

    if (!isValued(self.highChart)) {
        var highChart = self.createChart(chartConfig);
        var percentile = new ChartingPercentile(highChart);
        var intelligentAxis = new IntelligentAxis(highChart);
        self.percentile = percentile;
        self.intelligentAxis = intelligentAxis;
        self.highChart = highChart;
        axisType = self.highChart.getOptionParameter(KEY_AXIS_TYPE);
        self.setAxisType(axisType);
    }
}

PilotChart.prototype.createChart = function (chartConfig) {
    var self = this;
    var graph = Highcharts.StockChart(self.createDefaultOptions(chartConfig));
    return graph;
}
const colors = ["#FAD961", "#3591F1", "#D4486B", "#EF750D", "#C3F37E", "#40A731", "#12C7C8", "#007BF7", "#C056CD"];
const dataString = Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', new Date().getTime());

PilotChart.prototype.onChartLoad = function(chart){
     this.menuGenerator = new PilotChartMenuGenerator(chart,this); 
     this.menuGenerator.generateMenu(null);
}

PilotChart.prototype.getContextMenu = function(config){
    return this.menuGenerator.generateMenu(config);
}

PilotChart.prototype.createDefaultOptions = function (chartConfig) {
    var self = this;
    // this.legend = new ChartLegend();
    var options = {
        colors: colors,
        mergedOptions:mergeOptions(chartConfig.chartOptions,defaultOptions),
        credits: {
            enabled: false,
            text: "hhh",
            style: {
                "display": "none",
            }
        },
        lang: {
            noData: '暂无数据'
        },
        noData: {
            style: {
                fontWeight: 'bold',
                fontSize: '15px',
                color: '#303030'
            }
        },
        chart: {
            zoomType: 'x',
            alignTicks: false,
            // type: chartType,
            animation: false,
            reflow: true,
            renderTo: 'highChartsContainer',
            resetZoomButton: {
                enabled:false,
                position: {
                    x: 0,
                    y: 0
                },
                theme: {
                    // fill: 'white',
                    display: 'none',
                    stroke: 'silver',
                    r: 0,
                    width: 48,
                    height: 12,
                    style: {
                        fontSize: "9px"
                    },
                    states: {
                        hover: {
                            fill: '#41739D',
                            style: {
                                color: 'white'
                            }
                        }
                    }
                },
                relativeTo: 'chart'
            },
            spacingTop: 8,
            spacingRight: 5,
            spacingLeft: 2,
            // backgroundColor:"black",
            backgroundColor: {
                linearGradient: [200, 0, 200, 1000],
                stops: [
                    [0, 'rgba(0,255,237,0.00)'],
                    [1, 'rgba(0,197,255,0.43)']
                ]
            },
            style: {
                fontFamily: "inherit",
                fontSize: "inherit"
            },
            events: {
                load: function(e){
                    var chart = this;
                    self.onChartLoad(chart,e);
                },
                redraw: function (e) {
                    // console.log("chart redraw");
                    // self.onChartRedraw();
                }
            },
        },
        plotOptions: {
            series: {
                animation: false,
                events: {
                    mouseOver: function () {},
                },
                point: {
                    events: {
                        mouseOver: function (event) {}
                    }
                },
            },
            candlestick: {
                color: '#0084FF',
                lineColor:'white',
                upLineColor : 'white',
                upColor:'transparent',
                lineWidth:5,
                pointWidth:5

            },
            ohlc: {
                color: '#0084FF',
                lineColor:'white',
                upLineColor : 'white',
                upColor:'transparent',
                lineWidth:5,
                pointWidth:5

            }

        },
        series: [],
        exporting: {
            enabled: false,
        },
        global: {
            useUTC: true,
            timezoneOffset: new Date().getTimezoneOffset()
        },
        navigator: {
            enabled: false,
            // adaptToUpdatedData:false,
            // margin:10,
            // height:20,
            // maskInside:false
        },
        rangeSelector: {
            enabled: false,
            buttons: [{
                count: 1,
                type: 'minute',
                text: '1M'
            }, {
                count: 5,
                type: 'minute',
                text: '5M'
            }, {
                type: 'all',
                text: 'All'
            }],
            inputEnabled: false,
            selected: 0
        },
        scrollbar: {
            enabled: false //是否产生滚动条
        },
        tooltip: {
            enabled: true,
            //pointFormat: "<span style=\"color:{point.color}\">●</span> {series.name}: <b>{point.y:.3f}</b><br/>",
            dateTimeLabelFormats: dateTimeFormats,
            crosshairs: [true, true],
            headerFormat: "<span style=\"font-size: inherit\">{point.key}</span><br/>",
        },
        legend: {
            enabled: true,
            floating: true,
            verticalAlign: "top",
            align: "left",
            useHTML: true,
            layout: 'vertical',
            draggable: true,
            lastValues: {},
            title: {
                text: dataString,
                style: {
                    font: "PingFangSC-Regular",
                    color: "#FFFFFF",
                    fontSize: "10px",
                    fontWeight: "normal"
                }
            },
            margin: 20,
            backgroundColor: "#121A1C",
            itemDistance: 150,
            itemStyle: {
                fontFamily: "PingFangSC-Regular",
                fontSize: "10px",
                fontWeight: "normal"
            },
            borderWidth: 1,
            symbolWidth: 10,
            symbolHeight: 10,
            labelFormatter: labelFormatter
        },
        performance: {
            currentPriceIndicator: true,
            seriesTooltips: true
        },
        xAxis: [{
            crosshair: false,
            gridLineColor: '#618661',
            gridLineDashStyle: 'dot',
            gridLineWidth: 1,
            lineWidth: 0.5,
            labels: {
                useHTML: false,
                style: {
                    color: "#FFFFFF",
                    fontSize: "10px"
                }
            },
            ordinal: true,
            startOnTick: false,
            showLastLabel: false,
            endOnTick: true,
            minTickInterval: 250,
            tickPositioner: defaultXAxisPositioner,
            events: {
                afterSetExtremes: function (e) {
                    // console.log("afterSetExtremes",e,e.max,e.min);
                    self.setTimeSeries(e.dataMin, e.dataMax);
                },
                setExtremes: function (e) {
                    // console.log("setExtremes",e.max,e.min,e);
                    // TODO drag to get more data.
                    if (isValued(e.trigger) && e.trigger == "zoom" && isValued(e.target)) {
                        var dataMax = e.target.dataMax;
                        var dataMin = e.target.dataMin;
                        if ((dataMax - dataMin) / (e.min - dataMin) > 100) {
                            self.logger.info("dragToGetMoreData", e);
                            self.dragToGetMoreData(e.dataMin);
                        }
                    }
                    // if(e.min)
                }
            }
        }]
    }
    options.yAxis = createAxisOptions( 'DefaultAxis', {} );
    return options;
}

function defaultXAxisPositioner() {
    var positions = [];
    positions.info = this.tickPositions.info;
    this.tickPositions.forEach(function (position) {
      positions.push(position);
    });
  
    var padding = Math.floor((this.max - this.min ) * 0.03);
    var lastPosition = this.max + padding;
  
    positions.push(lastPosition);
    //store this so we can wack it later
    if ( isValued( positions.info ) ) {
      positions.info.paddingTick = lastPosition;
    }
          
  
    return positions;
  }
  
var createDefaultOptions = PilotChart.prototype.createDefaultOptions;

PilotChart.prototype._disableChartTypeSel = function(){
    var el = document.getElementById("select_chartType");
    el.disabled = !this.isDataSampled();
}

PilotChart.prototype.processQueryData = function (cachedSeriesData,isMore) {
    var self = this;
    isMore = isMore || false;
    if(self.isDataSampled()){
        if(isMore){
            
        }else{
            self.cachedSampleData = cachedSeriesData;
        }
    }
    self._disableChartTypeSel();
    for (const seriesName in cachedSeriesData) {
        const seriesData = cachedSeriesData[seriesName];
        var series = self.findSeriesByName(seriesName);
        if (!isValued(series)) {
            series = self.newSeries(seriesName);
        }
        self.addDataPointsToSeries(seriesData, seriesName,isMore);
        // console.log("processQueryData",seriesName);
    }
    self.structureRedraw();
    // TODO if it is intelligent , then invoke
    self.intelligentAxis.processSeries();
}

PilotChart.prototype.setLastestUpdateTime = function(lastestUpdateTime){
    document.getElementById("update-time-value").innerText = new Date(lastestUpdateTime).toLocaleTimeString();
}

PilotChart.prototype.processSubscribeData = function (seriesName, convertData) {
    // TODO remove this code 
    var self = this;
    var t = new Date(convertData[0]);
    t.setMilliseconds(0);
    convertData[0] = new Date(t).getTime();

    self.setLastestUpdateTime(convertData[0]);
    // console.log("processSubcribeData",seriesName);
    var series = self.findSeriesByName(seriesName);
    if (!isValued(series)) {
        series = self.newSeries(seriesName);
    }

    if (self.isDataSampled() ){
        self.processSubscribeSampleData(series, convertData);
    } else {
        self.addDataPointToSeries(convertData, series);
    }

    // if is tick data ,remove data
    if ((series.data.length > self.maxDataPoint) && !self.isDataSampled()) {
        series.removePoint(0, false, false);
    }
    self.structureRedraw();
}


PilotChart.prototype.processSubscribeSampleData = function (series, convertData) {
    var self = this;
    var intervalType = this.getSampleDataIntervalType(this.sampleInterval);
    var d = new Date(convertData[0]);
    var xnewValue, lastVaue, min;
    if(series.xData.length==0){

    }
    var lastTime = series.xData[series.xData.length - 1];
    var lastD = new Date(lastTime);
    var minsInterval = 1000 * 60;
    var hoursInterval = minsInterval * 60;
    var daysInterval = hoursInterval * 24;
    switch (intervalType) {
        case "m":
            xnewValue = d.getMinutes();
            lastVaue = lastD.getMinutes();
            min = Math.floor(xnewValue / (self.sampleInterval / minsInterval)) * (self.sampleInterval / minsInterval);
            // console.log("processSubcribeSampleData",xnewValue,lastVaue,min);
            d.setMinutes(min);
            d.setSeconds(0);
            d.setMilliseconds(0);
            break;
        case "h":
            xnewValue = d.getHours();
            lastVaue = lastD.getHours();
            min = Math.floor(xnewValue / (self.sampleInterval / hoursInterval)) * (self.sampleInterval / hoursInterval);
            d.setMinutes(0);
            d.setSeconds(0);
            d.setMilliseconds(0);
            d.setHours(min);

            break;
        case "d":
            xnewValue = d.getDay();
            lastVaue = lastD.getDay();
            min = Math.floor(xnewValue / (self.sampleInterval / daysInterval)) * (self.sampleInterval / daysInterval);
            d.setMinutes(0);
            d.setSeconds(0);
            d.setMilliseconds(0);
            d.setHours(0);
            d.setDate(min);
            break;
        default:
            self.logger.error("unsupport intervalType", intervalType);
            break;
    }
    if (min === lastVaue) {
        self.replaceWithOldValue(series, convertData, d);
    } else {
        self.insertNewValue(series, convertData, d);
    }
}

PilotChart.prototype.replaceWithOldValue = function (series, convertData, d) {
    var self = this;
    // TODO remove last data point with new value
    // console.log("replaceWithOldValue before : "+ self.cachedSampleData[series.name][self.cachedSampleData[series.name].length-1] +"with new value:" + convertData[1]);
    var ohlcVaules = self.cachedSampleData[series.name].pop();
    var newClose = convertData[1];
    convertData[0] = d.getTime();
    ohlcVaules[0] = d.getTime();
 
    var high = ohlcVaules[2];
    var low = ohlcVaules[3];
    if (newClose >= high) {
        ohlcVaules[2] = newClose;
    } else if (newClose <= low) {
        ohlcVaules[3] = newClose;
    } else {

    }
    ohlcVaules[4] = newClose;
    // console.log("replaceWithOldValue after : "+ ohlcVaules +"with new value:" + convertData[1]);
    series.removePoint(series.xData.length - 1, false, false);
    self.cachedSampleData[series.name].push(ohlcVaules);
    if(!self.isOHLC(self.chartType)){
        self.addDataPointToSeries(convertData, series);
    }else {
        self.addDataPointToSeries(ohlcVaules, series);
    }
}

PilotChart.prototype.insertNewValue = function (series, convertData, d) {
    var self = this;
    convertData[0] = d.getTime();
    var dataPoint = [convertData[0],convertData[1],convertData[1],convertData[1],convertData[1]];
    if(!isValued(self.cachedSampleData[series.name])){
        self.cachedSampleData[series.name] = [];
    }
    
    self.cachedSampleData[series.name].push(dataPoint);
    if(!self.isOHLC(self.chartType)){
        self.addDataPointToSeries(convertData, series);
    }else{
        // console.log("insertNewValue : "+ dataPoint +"with new value:" + convertData[1]);
        self.addDataPointToSeries(dataPoint, series);
    }
}

PilotChart.prototype.isOHLC = function (chartType) {
    if (!isValued(chartType)) throw new Error('chartType should not be null');
    if (chartType.toLowerCase() === "ohlc" || chartType.toLowerCase() === "candlestick") return true;
    return false;
}

PilotChart.prototype.getSampleDataIntervalType = function (sampleInterval) {
    var minsInterval = 1000 * 60;
    var hoursInterval = minsInterval * 60;
    var daysInterval = hoursInterval * 24;

    if (sampleInterval / minsInterval < 60) {
        return "m";
    } else if (sampleInterval / hoursInterval < 60) {
        return "h";
    } else if (sampleInterval / daysInterval < 24) {
        return "d";
    } else {
        return "w";
    }
}

PilotChart.prototype.structureRedraw = function (redraw) {
    var highChart = this.highChart;
    this.percentile.zoomToPercentile();
    if (highChart.legend) {
        highChart.legend.reformat();
      }
    this.highChart.redraw();

}

PilotChart.prototype.showLoading = function (msg) {
    this.loading = true;
    this.highChart.showLoading(msg);
}

PilotChart.prototype.hideLoading = function () {
    this.loading = false;
    this.highChart.hideLoading();
}


PilotChart.prototype.clearAllSeries = function () {
    this.cachedSampleData = null;
    this.highChart.clearAllSeries();
}

// TODO return highchart series 
PilotChart.prototype.findSeriesByName = function (seriesName) {
    return this.highChart.getSeriesByName(seriesName);
}



// TODO return highchart series 
PilotChart.prototype.newSeries = function (seriesName) {
    var self = this;
    var highCharts = self.highChart;
    var axisType = self.axisType;
    var seriesOptions = {
        "name": seriesName,
        "id": seriesName,
        "lineWidth": 1,
        "type": self.chartType,
        "step": false,
        "visible": true,
        "enableMouseTracking": true,
        "dataGrouping": {
            "enabled": true,
            "groupPixelWidth": 2,
            "dateTimeLabelFormats": dataGroupingTimeFormats
        },
        point: {
            events: {
                select: function (event) {
                    self.logger.log("point select");
                }
            }
        },
    };

    seriesOptions = highCharts.configSeriesOptions(seriesOptions);
    var yAxis = null;
    if(axisType =="own" && highCharts.getAllSeries().length>0){
        yAxis = assignYAxis(seriesName,{
            offset: highCharts.yAxis.length*36,
            x:(highCharts.yAxis.length)*18
        },highCharts);
    }
    if(yAxis){
        seriesOptions.yAxis = yAxis;
    }

    // if (seriesData.errorMessage) {
    //     //chances are there will be no data in error message series...turn off datagrouping
    //     seriesOptions.errorMessage = seriesData.errorMessage;
    //     seriesOptions.dataGrouping.enabled = false;
    // }
    // if (self.isOHLC(self.chartType)) {
    //     seriesOptions.type = self.chartType;
    //     seriesOptions.dataGrouping.groupPixelWidth = 20;
    //     seriesOptions.dataGrouping.enabled = true;
    //     seriesOptions.pointWidth = 5;
    // }



    self.logger.info("New Series ", seriesOptions);
    var series = highCharts.addSeries(seriesOptions, false);
    highCharts.colorYAxis();
    return series;
}

// TODO return highchart series 
PilotChart.prototype.addDataPointToSeries = function (dataPoint, series) {
    series.addPoint(dataPoint, false);
}

//TODO
PilotChart.prototype.addDataPointsToSeries = function (dataPoints, seriesName,isMore) {
    var self = this;
    if (!Array.isArray(dataPoints)) {
        throw new Error('dataPoints should be array, but now datapoints is :', dataPoints);
    }
    if (!isValued(seriesName)) {
        throw new Error('seriesName should be not null', seriesName);
    }
    // dataPoints.forEach((d)=>{
    //     self.addDataPiontToSeries(d,series);
    // });
    console.log("addDataPointsToSeries",dataPoints);
    var series = self.findSeriesByName(seriesName);
    if(!isMore){
        var data = [];
        data.push(...dataPoints);
        series.setData(dataPoints, false);
    }else{
        dataPoints.forEach((dataPoint)=>{
            series.addPoint(dataPoint,false,false);
        });
    }
}

PilotChart.prototype.setTitle = function (title) {
    var self = this;
    self.title = title;
    document.getElementById("chart-title").innerText = title;
}


PilotChart.prototype.setTimeSeries = function (min, max) {

    if (min) {
        document.getElementById("timeSerieStart").value = new Date(min).toLocaleDateString() + " " + new Date(min).toLocaleTimeString();
    }
    if (max) {
        document.getElementById("timeSerieEnd").value = new Date(max).toLocaleDateString() + " " + new Date(min).toLocaleTimeString();
    }
}


PilotChart.prototype.setAxisType = function (axisType){
    var self = this;
    var chart = this.highChart;
    self.logger.info("Requesting axis type: ", axisType);
    this.axisType = axisType;
    switch (STRING_UTILS.toLowerCase(axisType)) {
        case "intelligent":
            self.logger.info("Intelligent axis calc");
            self.intelligentAxis.processSeries();
            var setFunction = this.setAxisType.bind(this, axisType);
            if (!this._intelligentTimer) {
                var interval = chart.getOptionParameter(KEY_AXIS_INTELLIGENT_INTERVAL);
                self.logger.info("Intelligent axis timer set for ", interval, "seconds");
                this._intelligentTimer = window.setInterval(setFunction, interval * 1000);
                this._intelligentInterval = interval;
            } else {
                var currentInterval = chart.getOptionParameter(KEY_AXIS_INTELLIGENT_INTERVAL);
                if (currentInterval != this._intelligentInterval) {
                    clearInterval(this._intelligentTimer);
                    this._intelligentTimer = null;
                    //prep the next call..
                    window.setTimeout(setFunction, currentInterval);
                }
            }

            break;
        case "own":
            var processedSeriesCount = 0;
            chart.series.forEach(function (inSeries) {
                if (inSeries.linkedParent != null) {
                    inSeries.update({
                        yAxis: inSeries.linkedParent.yAxis.options.id
                    }, true);
                    return;
                }
                if (inSeries.isDerivedSeries()) {
                    inSeries.update({
                        yAxis: 0
                    }, true);
                    return;
                }

                while (processedSeriesCount + 1 > this.yAxis.length) {
                    assignYAxis("axis-" + (this.yAxis.length).toString(), {
                        offset: this.yAxis.length*36,
                        x:(this.yAxis.length)*18
                    },this);
                }
                if (inSeries.yAxis.options.index != processedSeriesCount) {
                    inSeries.update({
                        yAxis: processedSeriesCount
                    }, true);
                }
                processedSeriesCount++;
            }.bind(chart));
            break;
        case "shared":
        chart.series.forEach(function (inSeries) {
                if (inSeries.yAxis.options.index != 0) {
                    this.yAxis[0].update(this.getAxisColorOptions(), true);
                    inSeries.update({
                        yAxis: 0
                    }, true);
                }
            }.bind(chart));

            break;
    };
    if (AXIS_TYPE_INTELLIGENT != axisType && isValued(this._intelligentTimer)) {
        logger.info("Cleared intelligent axis timer");
        window.clearInterval(this._intelligentTimer);
    }

    chart.removeUnusedYAxis();
    chart.colorYAxis();
    this.percentile.zoomToPercentile();
    chart.setOptionParameter(KEY_AXIS_TYPE, axisType);
}

/**
 * @description set menu click event call back 
 * @param {MenuClickCallBack} menuClickCallBack - pilot chart range selector menu click event callBack
 */
PilotChart.prototype.setClickRangeSelectorCallback = function () {
    var self = this;
    var els = document.getElementsByClassName("range-selector")[0].children;
    for (const el of els) {
        el.addEventListener("click", function (event) {
            var type = this.getAttribute("menu-type");
            var count = this.getAttribute("menu-count");
            var currentTime = new Date().getTime();
            var offsetTimeStamp = getTimeOffset(type, count, currentTime);
            var dataExtremes = self.getExtremes();
            if (!isValued(dataExtremes)) {
                self.logger.warn("chart not init");
                return;
            }
            var min = dataExtremes.dataMin;

            if (min <= offsetTimeStamp) {
                //just move livewindow;
                var axis = self.highChart.xAxis[0];
                axis.setExtremes(offsetTimeStamp, dataExtremes.dataMax, true, false);
            } else {
                //TODO get more data from server
                if (self.requestMoreDataEvent) {
                    self.requestMoreDataEvent(currentTime - offsetTimeStamp,min);
                } else {
                    self.logger.warn("requestMoreDataEvent should be set in PilotChartEvent");
                }
            }

            // if(self.rangeSelectorMenuClickEvent && typeof self.rangeSelectorMenuClickEvent =="function"){
            //     self.rangeSelectorMenuClickEvent(type,count,this);
            // }else{
            //     self.logger.warn("rangeSelectorMenuClickEvent should be set in PilotChartEvent");
            // }
        });
    }
}
PilotChart.prototype.setChartTypeSelectCallback = function(){
    var self = this;
    var el = document.getElementById("select_chartType");
    el.addEventListener("change",function(event){
        if(self.isDataSampled()){
            self.setChartType(el.value);
        }else{
            self.logger.warn("tick data can not change chart type");
        }

    });
}

PilotChart.prototype.setChartType = function(chartType){
    var self = this;
    self.chartType = chartType;
    var allSeries = self.highChart.getAllSeries();
    allSeries.forEach(series => {
        // series.setData(series.options.data,true);
        var options = {
            type:chartType,
            data:self.isOHLC(chartType)?  self.cachedSampleData[series.name]: self.cachedSampleData[series.name].map((v)=>{
                return [v[0],v[4]];
            })
        }
        series.update(options);
        this.highChart.colorYAxis();
        // var options = series.options;
    });
}

PilotChart.prototype.getExtremes = function () {
    if (isValued(this.highChart) && isValued(this.highChart.xAxis)) {
        var axis = this.highChart.xAxis[0];
        return axis.getExtremes();
    } else {
        return null;
    }
}




/**
 * @private
 * @description request more data from server when drag from left to right 
 * @param {number} dataMin: the hist end time
 * @param {number} timeStampOffset: timeStamp offset of end time, can be null , if set null, will get default vaule.
 * 
 * @example if dataMin is 1557452491810 , and timeStampOffset is 1000*3600 (i hour), then hist start time will be  (1557452491810 - 1000*3600) 
 */
PilotChart.prototype.dragToGetMoreData = function (dataMin, timeStampOffset) {
    if (this.requestMoreDataEvent) {
        this.requestMoreDataEvent(dataMin-timeStampOffset, dataMin);
    } else {
        this.logger.warn("requestMoreDataEvent should be set in PilotChartEvent");
    }
}


PilotChart.prototype.changeDataInterval = function (sampleInterval,maxDataPoint) {
    var self = this;
    if (this.sampleInterval == sampleInterval) {
        return;
    }
    this.logger.log(`changeDataInterval from current ${this.sampleInterval} to ${sampleInterval}`);
    this.sampleInterval = sampleInterval;
    this.maxDataPoint = maxDataPoint;
    this._disableChartTypeSel();
    if (this.dataIntervalChangedEvent) {
        //TODO   request data from server or cache
        this.clearAllSeries();
        this.dataIntervalChangedEvent(sampleInterval,maxDataPoint);
    } else {
        self.logger.warn("dataIntervalChangedEvent should be set in PilotChartEvent");
    }
}

/**
 * @typedef PilotChartEvent
 * @description PilotChartEvent
 * @type {object}
 * @property {function} [requestMoreDataEvent] - this event will only occur in drag from left to right, and chart have no more date
 * @property {function} [intervalChangedEvent] - this event will occur when changed chart dateType, sampleData or tickData
 */


/**
 * @description set up request from chart to controller
 * @param {PilotChartEvent} pilotChartEvent
 */

PilotChart.prototype.setPilotChartEvent = function (pilotChartEvent) {
    this.requestMoreDataEvent = pilotChartEvent.requestMoreDataEvent;
    this.intervalChangedEvent = pilotChartEvent.intervalChangedEvent;
    // this.rangeSelectorMenuClickEvent = pilotChartEvent.rangeSelectorMenuClickEvent;
}




